home *** CD-ROM | disk | FTP | other *** search
/ Aminet 5 / Aminet 5 - March 1995.iso / Aminet / util / misc / x10ctrl.lha / x10ctrl.c < prev    next >
C/C++ Source or Header  |  1994-01-21  |  84KB  |  2,330 lines

  1. /* ========================  X10CTRL.C   ================================= */
  2. /*  (c) 1988, Stephen L. Childress. 818/706-5247
  3.  
  4.  Main Program.
  5.  
  6.  Amiga 500/1000/2000 program to manage the X10 USA, Inc. CP290
  7.   computer interface ($35). This device connects to an Amiga (or other computer)
  8.   via an RS232 serial port. With this software, the user can establish
  9.   on/off/dim events of a specified duration for specific days of the week.
  10.   This is done by drawing lines on a graphics screen with the mouse.
  11.   Having done so, this event data can be down-loaded to the CP290 box.
  12.   From this point, the CP290 will perform the event data forever, without
  13.   further help from the Amiga.
  14.  
  15.   This software also enables the user to up-load the event data to the
  16.   Amiga, view it on the graphics screen, and save it to disk. Lastly, the
  17.   user can issue an immediate X10 command to an X10 module, from the
  18.   Amiga keyboard.
  19.  
  20.  
  21. Makefile:  (Lattice C)
  22.  
  23. x10ctrl: x10ctrl.o x10struct.o
  24.     blink TO x10ctrl FROM lib:c.o x10ctrl.o x10struct.o \
  25.     LIB lib:lc.lib lib:amiga.lib
  26.  
  27. x10ctrl.o: x10ctrl.c x10ctrl.h
  28.     lc x10ctrl.c
  29.  
  30. x10struct.o: x10struct.c x10ctrl.h
  31.     lc x10struct.c
  32.  
  33.  
  34.  
  35.  
  36. *******************************************************/
  37.  
  38.  
  39.  
  40. #include <exec/types.h>
  41. #include <exec/exec.h>
  42. #include <dos.h>
  43. #include <graphics/view.h>
  44. #include <graphics/display.h>
  45. #include <intuition/intuition.h>
  46. #include <devices/serial.h>
  47. #include <stdio.h>
  48. #include "x10ctrl.h"
  49.  
  50. char * stpchr();
  51. UWORD * ColorTableAddr;
  52. struct ColorMap *ColorMapAddr;
  53. struct ViewPort *ViewPortAddr(), *vpa;
  54. extern USHORT colortable[];
  55.  
  56. char datafilename[64], scratchbuf[64];
  57.  
  58. extern struct Gadget            /* see X10STRUCT.C */
  59.         gadNAME,
  60.         gadFROMX10,
  61.         gadX10COMMAND,
  62.         gadSECURITY,
  63.         gadNEWFILE,
  64.         gadWEEKEND,
  65.         gadWEEKDAYS,
  66.         gadSUN,
  67.         gadSAT,
  68.         gadFRI,
  69.         gadTHURS,
  70.         gadWED,
  71.         gadTUES,
  72.         gadMON,
  73.         gadSETNAME,
  74.         gadDIMUP,
  75.         gadDIMDN,
  76.         gadOFF,
  77.         gadON,
  78.         gadX10DATE,
  79.         gadTOX10,
  80.         gadNEXT,
  81.         gadDEL,
  82.         gadQUIT,
  83.         gadSETBASE,
  84.         gadEARLIER,
  85.         gadLATER,
  86.         gadLONGER,
  87.         gadSHORTER;
  88.  
  89. extern struct IntuiText
  90.         savemsgbody,
  91.         savemsgyes,
  92.         savemsgno,
  93.         ynmessage,
  94.         yesmsg,
  95.         nomsg,
  96.         gadNAMEmsg;
  97.  
  98. extern struct StringInfo nameinfo;
  99.  
  100.  
  101. /*** Things related to the serial port:         ***/
  102.  
  103. extern struct MsgPort *CreatePort();
  104. struct IOExtSer IORser;      /* Serial port IO request block */
  105. int Serialisopen = 0;
  106.  
  107.  
  108.  
  109. /** beware of changing this! */
  110. int minutesK = 60 / HourSpacing; /* pixels per minute */
  111.  
  112.  
  113. #if 0
  114.  
  115. /* ================================================================= */
  116. /* This table has the time of sunset for the 1st day of each month.
  117.    The times are GMT standard time, 24hr notation, e.g., 1800 = 6PM.
  118.    Taken from a 1984 almanac. The times are for 30 degrees North Latitude.
  119. */
  120.  
  121. SHORT sunsettable[] = {
  122. /*  Jan   Feb   Mar   Apr   May   Jun   Jul   Aug   Sep   Oct   Nov   Dec */
  123.         1711, 1737, 1800, 1819, 1837, 1856, 1905, 1853, 1822, 1745, 1713, 1700
  124.         };
  125.  
  126. /* Table of corrections, by month, for sunset, to account for Daylight Savings
  127.    time. This table assumes Daylight Savings is practiced. */
  128. SHORT dsmonths[] = {
  129.     0,    0,    0,    0,    1,    1,    1,    1,    1,    1,    0,    0
  130.         };
  131. #endif
  132.  
  133.  
  134.  
  135.  
  136. /* ================================================================= */
  137.  
  138. struct Events {
  139.         USHORT
  140.                         link,
  141.                         xstart,
  142.                         xstop;
  143.         UBYTE
  144.                         devicecode,
  145.                         days,
  146.                         command,
  147.                         dimness,
  148.                         flags;
  149. } Events[recordlimit+1];
  150.  
  151.  
  152. int devicelist[deviceMax+1];
  153.  
  154. int     mousex,
  155.         mousey,
  156.         xmax,
  157.         Devnum,
  158.         devicey,
  159.         Eventnum = 0,
  160.         oldx,
  161.         gadPspacing = gadCspacing * charwidth,
  162.         infoline = gadline-3,
  163.         infowidth = 79 - infocol,
  164.         error,
  165.         Signalflag,
  166.         Changed = 0,
  167.         DevAreaY,
  168.         infox,
  169.         infoy,
  170.         Daymask = 0x7f,
  171.         BaseHouseCode = 1,
  172.         yesyesflag,
  173.         verbose = VERBOSE;      /* see the .h */
  174.  
  175. int clas,  code;
  176.  
  177. UBYTE X10cmd[256];
  178.  
  179. char textbuf[256];
  180.  
  181. struct Window *sbwindow = NULL;
  182. struct Window *window, *OpenWindow();      /* returns ptr to structure */
  183. struct Screen *screen, *OpenScreen();
  184.  
  185. struct IntuiMessage *GetMsg(), *Message;
  186. struct IntuitionBase *IntuitionBase;
  187. struct IntuiText intuitext;
  188.  
  189. char days[8][4] = { {"__"},{"M "},{"Tu"},{"W "},{"Th"},{"F "},{"Sa"},{"Su"} };
  190.  
  191. char bsr[6][8] = {  {"NONE"},   /* 0  these correspond to bsrON, bsrOFF... */
  192.                                         {"NONE"},       /* 1 */
  193.                                         {"ON  "},       /* 2 */
  194.                                         {"OFF "},       /* 3 */
  195.                                         {"NONE"},       /* 4 */
  196.                                         {"DIM "} };     /* 5 */
  197.  
  198. /* This table is indexed 0..n for housecode 1..16 to
  199.    yield the X10 version of that housecode. So housecode=2 ('B') = hex E0 */
  200. UBYTE Housecodes[] = { 0x00,
  201.                                           0x60, 0xE0, 0x20, 0xA0,
  202.                                           0x10, 0x90, 0x50, 0xD0,
  203.                                           0x70, 0xF0, 0x30, 0xB0,
  204.                                           0x00, 0x80, 0x40, 0xC0 }; /* see pg 10 of X10 manual */
  205.  
  206.  
  207. char devicenames[deviceMax+1][DEVNAMELEN];
  208.  
  209.  
  210. struct RastPort *Rport,
  211.                                 *sbRport = NULL;
  212. struct MsgPort *Intuiport;
  213. struct AreaInfo ainfo;
  214.  
  215. PLANEPTR myplane;
  216. #define TMPRASX 640             /* see AllocRas() herein */
  217. #define TMPRASY 32
  218.  
  219. struct GfxBase *GfxBase;
  220.  
  221. APTR Intuimsg;          /* see call to GetMsg() herein */
  222.  
  223. FILE *datafp;
  224.  
  225. char nwname[] = "    Computerized Home Control Manager for the X10 CP290.";
  226.  
  227. struct NewScreen X10screen =
  228.         {
  229.         0, 0, SCREENMAXX, SCREENMAXY,           /* size of screen */
  230.         4,                                      /* depth */
  231.         PENTEXT1, CYAN,                         /* pens */
  232.         HIRES | INTERLACE | SPRITES,
  233.         CUSTOMSCREEN,
  234.         NULL,                           /* font */
  235.         (UBYTE *) nwname,
  236.         NULL,                           /* gadgets */
  237.         NULL                            /* custom bit map */
  238.         };
  239.  
  240.  
  241. struct NewWindow nw =
  242.         {
  243.         0,0,                                   /* LeftEdge and TopEdge */
  244.         SCREENMAXX, SCREENMAXY,                /* Width and Height */
  245.         PENTEXT1, BLACK,                       /* DetailPen and BlockPen */
  246.                                                                                    /* IDCMP Flags with Flags below */
  247.         CLOSEWINDOW | REFRESHWINDOW | MOUSEBUTTONS | GADGETUP,
  248.  
  249.         WINDOWDEPTH | WINDOWCLOSE | SMART_REFRESH | ACTIVATE | REPORTMOUSE,
  250. #if 1
  251.         &gadQUIT, NULL,                            /* Gadget and Image pointers */
  252. #else
  253.         NULL, NULL,                            /* Gadget and Image pointers */
  254. #endif
  255.         nwname,
  256.         NULL,                                  /* Screen ptr null (this screen) */
  257.         NULL,                                  /* BitMap pointer */
  258.         SCREENMAXX, SCREENMAXY,                /* MinWidth and MinHeight */
  259.         SCREENMAXX, SCREENMAXY,                /* MaxWidth and MaxHeight */
  260.         CUSTOMSCREEN                           /* Type of window */
  261.         };
  262.  
  263.  
  264. struct NewWindow nw1 =
  265.         {
  266.         50, 50,                                 /* LeftEdge and TopEdge */
  267.         nw1X, nw1Y,                              /* Width and Height */
  268.         PENTEXT1, BLACK,                           /* DetailPen and BlockPen */
  269.                                                                                    /* IDCMP Flags with Flags below */
  270.         CLOSEWINDOW | REFRESHWINDOW | MOUSEBUTTONS | GADGETUP,
  271.  
  272.         WINDOWCLOSE | SMART_REFRESH | ACTIVATE,
  273.         &gadNAME, NULL,                            /* Gadget and Image pointers */
  274.         "Please...",            /* Title string */
  275.         NULL,                                  /* Screen ptr null (this screen) */
  276.         NULL,                                  /* BitMap pointer */
  277.         nw1X, nw1Y,                            /* MinWidth and MinHeight */
  278.         nw1X, nw1Y,                            /* MaxWidth and MaxHeight */
  279.         CUSTOMSCREEN                           /* Type of window */
  280.         };
  281.  
  282. struct NewWindow standbywindow =
  283.         {
  284.         GADx, GADy-8,                                 /* LeftEdge and TopEdge */
  285.         640-GADx, 400-GADy+8,                              /* Width and Height */
  286.         GREEN, RED,                           /* DetailPen and BlockPen */
  287.                                                                                    /* IDCMP Flags with Flags below */
  288.         REFRESHWINDOW | MOUSEBUTTONS | GADGETUP,
  289.  
  290.         SMART_REFRESH | ACTIVATE,
  291.         NULL, NULL,                            /* Gadget and Image pointers */
  292.         "                            B-B-B-BUSY - PLEASE WAIT!  ",/* Title string */
  293.         NULL,                                  /* Screen ptr null (this screen) */
  294.         NULL,                                  /* BitMap pointer */
  295.         nw1X, nw1Y,                            /* MinWidth and MinHeight */
  296.         nw1X, nw1Y,                            /* MaxWidth and MaxHeight */
  297.         CUSTOMSCREEN                           /* Type of window */
  298.         };
  299.  
  300.  
  301. /* ================================================================= */
  302.  
  303.  
  304.  
  305. int
  306. main()
  307. {
  308.         register int i, j, more;
  309.         int n;
  310.         int error, x, x1, days, command, dimness, class, flags;
  311.         register char *p;
  312. /***
  313.                 struct IntuiText *;
  314.                 struct Gadget *gad;
  315. */
  316.  
  317. /*** Open serial port and set baud rate, etc., for the X10 box.
  318. */
  319.  
  320.     IORser.io_SerFlags |= SERF_SHARED;
  321.     if ((error = OpenDevice (SERIALNAME, 0, &IORser, 0)) != 0) {
  322.         printf( "Unable to open Serial Device, error=%ld\n", error );
  323.         exit(20);
  324.     }
  325.  
  326.         i = (int)
  327.                 (IORser.IOSer.io_Message.mn_ReplyPort = CreatePort("SetSerial", 0));
  328.         if (i == NULL) {
  329.         printf( "Unable to create port for IO message\n" );
  330.         CloseDevice(&IORser);
  331.                 exit(20);
  332.         }
  333.         ++Serialisopen;
  334.  
  335. /*** Read serial port control settings. Then change them to
  336.          the values appropriate for the X10 box.
  337. */
  338.  
  339.     IORser.IOSer.io_Command = SDCMD_QUERY;
  340.     if (error = DoIO( &IORser ) != 0) {
  341.         printf ( "Query status error %ld\n", error);
  342.         cleanup();
  343.                 exit(20);
  344.     }
  345.  
  346.         IORser.io_Baud = 600;
  347.         IORser.io_StopBits = 1;
  348.         IORser.io_WriteLen = 8;
  349.         IORser.io_ReadLen  = 8;
  350.         IORser.io_SerFlags = 0;
  351.  
  352.     IORser.io_SerFlags |= SERF_XDISABLED;
  353.  
  354.         IORser.IOSer.io_Command = SDCMD_SETPARAMS;
  355.  
  356.     if (error = DoIO( &IORser) != 0)  {
  357.                 printf("Serial I/O SETPARAMS error\n");
  358.                 cleanup();
  359.                 exit(20);
  360.         }
  361.  
  362.         for (i = 1; i <= 16; ++i)
  363.                 X10cmd[i] = 0xff;               /* build X10 cmd header */
  364.  
  365.         infox = infocol  * charwidth;
  366.         infoy = infoline * charwidth;
  367.  
  368.         purge();        /* erase all events, initialize strings, etc. */
  369.  
  370.  
  371.  
  372.  
  373.  
  374.         IntuitionBase =
  375.                 (struct IntuitionBase *) OpenLibrary ("intuition.library", 0);
  376.         if (IntuitionBase == NULL)  {
  377.                 printf("Open Intuition failed\n");
  378.                 exit(50);
  379.         }
  380.  
  381.         GfxBase =
  382.                 (struct GfxBase *) OpenLibrary ("graphics.library", 0);
  383.         if (GfxBase == NULL)  {
  384.                 printf("Open graphics failed\n");
  385.                 exit(50);
  386.         }
  387.  
  388.         screen = OpenScreen(&X10screen);
  389.         if (screen == NULL)  {
  390.                 printf("OpenScreen failed\n");
  391.                 exit(50);
  392.         }
  393.  
  394.         nw.Screen = screen;
  395.  
  396.    if ((window = OpenWindow(&nw)) == NULL) {
  397.       printf("OpenWindow failed\n");
  398.       cleanup();
  399.       exit(20);
  400.    }
  401.  
  402.  
  403.  
  404.  
  405.         Signalflag = 1 << window->UserPort->mp_SigBit;
  406.         Intuiport = window->UserPort;
  407.         Rport = window->RPort;
  408.  
  409. /*** vpa = ViewPortAddress(window);
  410.         ColorMapAddr   = vpa -> ColorMap;
  411.         ColorTableAddr = (UWORD *) ColorMapAddr -> ColorTable;
  412. ****/
  413.  
  414.  
  415.         LoadRGB4(ViewPortAddress(window), &colortable[0], 16);
  416.         strcpy(datafilename, DATAFILENAME);
  417.  
  418.  
  419. top:
  420.  
  421.         purge();
  422.         Eventnum = Devnum = 0;
  423.         TimeGraticule();        /* create gaticule displays */
  424.         hourlines();            /* redraw the hour lines */
  425.         info(0);                        /* setup blank info window in lower right of screen */
  426.         setdategadgets();       /* turn off all day-of-week gadgets */
  427.         ScreenToFront(screen);  /* WB screen requester can push us to the back */
  428.  
  429.  
  430.  
  431. /*** Reload X10 Event data from ASCII disk file.  */
  432.  
  433. reopen0:
  434.         p = " Event Data Disk File Name (Click CLOSE gadget if none) ? ";
  435.         goto reopen2;
  436. reopen1:
  437.         p = " Unable to open file. New Name? ";
  438. reopen2:
  439.         if ((i = getfilename(p)) < 0)  {
  440.                 cleanup();
  441.                 exit(20);
  442.         }
  443.  
  444.         if (i == 1)
  445.                 goto reopen0;                   /* name strlen == 0 */
  446.  
  447.         if (i == 2)
  448.         goto withoutfile;                       /* user closed the window */
  449.  
  450.  
  451.  
  452.  
  453.         datafp = fopen(datafilename, "r");
  454.         if (datafp == NULL)
  455.                 goto reopen1;
  456.  
  457.         more = 1;
  458.         n = 1;
  459.         while (more)  {
  460.                 /*** note: the intermediate variables, e.g., x and x1 below, had to
  461.                          be used as Lattice C did not compute address of (& operator)
  462.                                  correctly for an array of structures (Events[])
  463.                 ***/
  464.  
  465.                 i =     fscanf(datafp, "%d,%d,%d,%d,%d,%d,%d\n",
  466.                                                         &Devnum,
  467.                                                         &x,
  468.                                                         &x1,
  469.                                                         &days,
  470.                                                         &command,
  471.                                                         &dimness,
  472.                                                         &flags );
  473.                 Events[n].devicecode = Devnum;
  474.                 Events[n].xstart = x;
  475.                 Events[n].xstop = x1,
  476.                 Events[n].days = days;
  477.                 Events[n].command = command;
  478.                 Events[n].dimness = dimness;
  479.                 Events[n].flags = flags;
  480.  
  481.  
  482.                 if (Devnum > 0 && Devnum <= deviceMax)  {
  483.                         i = devicelist[Devnum];
  484.                         if (i == 0)
  485.                                 devicelist[Devnum] = n;
  486.                         else  {
  487.                                 while (Events[i].link)
  488.                                         i = Events[i].link;
  489.                                 Events[i].link = n;
  490.                         }
  491.                         Events[n].link = 0;
  492.                         ++n;
  493.                 }
  494.                 else  {
  495.                         --more;
  496.                 }
  497.         }
  498.  
  499. /*** Now read the names of the X10 devices: A5 is Porch light, etc.
  500. */
  501.  
  502.         more = 2;
  503.  
  504.         while (more && (feof(datafp) == 0) )  {
  505.                 if (fgets(textbuf, sizeof(textbuf), datafp) != NULL)  {
  506.                         stcd_i(textbuf, &n);    /* Lattice function: ASCII to int */
  507.                         p = stpchr(textbuf, '"');
  508.                         if (p != NULL)  {
  509.                                 j = strlen(++p) - 2;  /* 2 because of closing " and \n   */
  510.                                 if (j >= DEVNAMELEN)
  511.                                         j  = DEVNAMELEN;
  512.                                 if (j > 0 && n > 0 && n <= deviceMax)   /* if valid device no. */
  513.                                         strncpy(&devicenames[n], p, j);
  514.                         }
  515.                 }
  516.                 else
  517.                         --more;
  518.         }
  519.         fclose(datafp);
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529. withoutfile:
  530.  
  531.  
  532.         Eventnum = Devnum = 0;
  533.         RenderAllEvents();      /* display graphs for all events */
  534.  
  535. /*      gad = &gadMON;
  536.         for (i = 0; i <= 6; ++i)  {
  537.                 intuitext = gad->GadgetText;
  538.                 intuitext->FrontPen = (UBYTE) ( (~(DAYCOLOR0 + i)) & 15);
  539.                 gad = gad->NextGadget;
  540.         }
  541. ******/
  542.  
  543.  
  544.  
  545.  
  546. /************************ M A I N   L O O P ********************/
  547.  
  548.  
  549.         for ( ;; )  {
  550.                 /*** Discard queued up mouse messages */
  551.                 while ( (Message = GetMsg(Intuiport)) != 0)
  552.                         ReplyMsg(Message);
  553.                 SetSignal(0, Signalflag);
  554.  
  555.  
  556.  
  557.                 if ((Message = GetMsg(Intuiport)) == 0) { /*** Get a new mouse message */
  558.                         Wait(Signalflag);
  559.                         Message = GetMsg(Intuiport);
  560.                 }
  561.  
  562.                 Intuimsg = (APTR)Message->IAddress; /* for gadgets, points to gadget*/
  563.  
  564.                 class  = Message->Class;
  565.                 code   = Message->Code;
  566.                 mousex = window->MouseX;
  567.                 mousey = window->MouseY;
  568.                 ReplyMsg(Message);
  569.  
  570.  
  571. /* ================================================================= */
  572.  
  573.                 Daymask = Events[Eventnum].days;
  574.  
  575.                 /*** Process mouse action: Gadget or clicked on a pixel */
  576.  
  577.                 switch (class)  {
  578.  
  579.                         case GADGETUP:          /* button released on a Gadget */
  580.  
  581.                                         if (Intuimsg == (APTR)&gadQUIT)  { /* "QUIT" */
  582.                                                 goto signoff;
  583.                                         }
  584.  
  585.                                         if (Intuimsg == (APTR)&gadFROMX10) { /* UP-LOAD */
  586.                                                 Eventnum = 0;
  587.                                                 if (Changed)
  588.                                                         savedata();
  589.                                                 standby(1);
  590.                                                 if ((n = upload()) != 0)  {
  591.                                                         if (n != -1)  /* if -1, msg was done by upload() */
  592.                                                                 yesyes("Error reading events from CP2910 (X10)");
  593.                                                 }
  594.                                                 ++Changed;
  595.                                                 standby(0);
  596.                                                 break;
  597.                                         }
  598.  
  599.                                         if  (Intuimsg  ==  (APTR)&gadEARLIER)  {  /*   EARLIER   */
  600.                                                 if (Eventnum == 0)
  601.                                                         pleasemodule();
  602.                                                 else {
  603.                                                         x = Events[Eventnum].xstart;
  604.                                                         if (validspan(Eventnum,
  605.                                                                         --x, Events[Eventnum].xstop) == 0)  {
  606.                                                                 RenderOneEvent(-1, Eventnum, NULL);
  607.                                                                 Events[Eventnum].xstart = x;
  608.                                                                 --Events[Eventnum].xstop;
  609.                                                                 RenderOneEvent(RED, Eventnum, NULL);
  610.                                                                 info(0);
  611.                                                                 ++Changed;
  612.                                                         }
  613.                                                         else
  614.                                                                 printf("validspan=%d\n",
  615.                                                                   validspan(Eventnum,x, Events[Eventnum].xstop));
  616.                                                 }
  617.                                                 break;
  618.                                         }
  619.  
  620.                                         if  (Intuimsg  ==  (APTR)&gadLATER)  {  /*   LATER   */
  621.                                                 if (Eventnum == 0)
  622.                                                         pleasemodule();
  623.                                                 else {
  624.                                                         x = Events[Eventnum].xstop;
  625.                                                         if (validspan(Eventnum,
  626.                                                                         Events[Eventnum].xstart, ++x) == 0)  {
  627.                                                                 RenderOneEvent(-1, Eventnum, NULL);
  628.                                                                 ++Events[Eventnum].xstart;
  629.                                                                 Events[Eventnum].xstop = x;
  630.                                                                 RenderOneEvent(RED, Eventnum, NULL);
  631.                                                                 info(0);
  632.                                                                 ++Changed;
  633.                                                         }
  634.                                                 }
  635.                                                 break;
  636.                                         }
  637.  
  638.  
  639.  
  640.                                         if  (Intuimsg  ==  (APTR)&gadLONGER)  {  /*   LONGER   */
  641.                                                 if (Eventnum == 0)
  642.                                                         pleasemodule();
  643.                                                 else {
  644.                                                         x = Events[Eventnum].xstop;
  645.                                                         if (validspan(Eventnum,
  646.                                                                         Events[Eventnum].xstart, ++x) == 0)  {
  647.                                                                 RenderOneEvent(-1, Eventnum, NULL);
  648.                                                                 Events[Eventnum].xstop = x;
  649.                                                                 RenderOneEvent(RED, Eventnum, NULL);
  650.                                                                 info(0);
  651.                                                                 ++Changed;
  652.                                                         }
  653.                                                 }
  654.                                                 break;
  655.                                         }
  656.  
  657.                                         if  (Intuimsg  ==  (APTR)&gadSHORTER)  {  /*   SHORTER   */
  658.                                                 if (Eventnum == 0)
  659.                                                         pleasemodule();
  660.                                                 else {
  661.                                                         x = Events[Eventnum].xstop;
  662.                                                         if (validspan(Eventnum,
  663.                                                                         Events[Eventnum].xstart, --x) == 0)  {
  664.                                                                 RenderOneEvent(-1, Eventnum, NULL);
  665.                                                                 Events[Eventnum].xstop = x;
  666.                                                                 RenderOneEvent(RED, Eventnum, NULL);
  667.                                                                 info(0);
  668.                                                                 ++Changed;
  669.                                                         }
  670.                                                 }
  671.                                                 break;
  672.                                         }
  673.  
  674.  
  675.  
  676.                                         if (Intuimsg == (APTR)&gadTOX10) { /* DOWN-LOAD */
  677.                                                 standby(1);
  678.                                                 if ((n = download()) != 0)
  679.                                                         notresponding(n);
  680.                                                 standby(0);
  681.                                                 break;
  682.                                         }
  683.  
  684.  
  685.                                         if (Intuimsg == (APTR)&gadNEXT)  { /* "NEXT" */
  686.                                                 if (Eventnum) {
  687.                                                         Eventnum = successor(Eventnum);
  688.                                                         RenderOneDevice(Devnum);
  689.                                                         info(0);
  690.                                                         setdategadgets();
  691.                                                 }
  692.                                                 else
  693.                                                         pleasemodule();
  694.                                                 break;
  695.                                         }
  696.  
  697.                                         if (Intuimsg == (APTR)&gadX10COMMAND) { /* X10COMMAND */
  698.                                                 if (Eventnum)  {
  699.                                                         standby(1);
  700.                                                         if ((n = x10command()) != 0)
  701.                                                                 notresponding(n);
  702.                                                         standby(0);
  703.                                                 }
  704.                                                 else
  705.                                                         pleasemodule();
  706.                                                 break;
  707.                                         }
  708.  
  709.                                         if (Intuimsg == (APTR)&gadSETNAME)  { /* "SET NAME" */
  710.                                                 if (Eventnum)
  711.                                                         setname();
  712.                                                 else
  713.                                                         pleasemodule();
  714.                                                 break;
  715.                                         }
  716.  
  717.                                         if (Intuimsg == (APTR)&gadSETBASE)  { /* "SET BASE" */
  718.                                                 if (yesno(" Erases Displayed Events! ")) {
  719.                                                         if (setbase() == 0)  {  /* get new Basecode */
  720.                                                                 purge();                        /* erase all */
  721.                                                                 Eventnum = 0;
  722.                                                                 TimeGraticule();
  723.                                                                 info(0);
  724.                                                                 setdategadgets();
  725.                                                         }
  726.                                                 }
  727.                                                 break;
  728.                                         }
  729.  
  730.                                         if (Intuimsg == (APTR)&gadDEL)  { /* "DELETE" */
  731.                                                 if (Eventnum)  {
  732.                                                         DeleteEvent(Eventnum);
  733.                                                         info(0);
  734.                                                         setdategadgets();
  735.                                                 }
  736.                                                 else
  737.                                                         pleasemodule();
  738.                                                 break;
  739.                                         }
  740.  
  741.                                         if (Intuimsg == (APTR)&gadX10DATE)  { /* "SET DATE" */
  742.                                                 standby(1);
  743.                                                 x10date();
  744.                                                 standby(0);
  745.                                                 break;
  746.                                         }
  747.  
  748.  
  749.                                         if (Intuimsg == (APTR)&gadON)   { /* "ON" */
  750.                                                 if (Eventnum)  {
  751.                                                         ++Changed;
  752.                                                         Events[Eventnum].command = bsrON;
  753.                                                         info(0);
  754.                                                 }
  755.                                                 else
  756.                                                         pleasemodule();
  757.                                                 break;
  758.                                         }
  759.  
  760.                                         if (Intuimsg == (APTR)&gadOFF)  { /* "OFF" */
  761.                                                 if (Eventnum)  {
  762.                                                         ++Changed;
  763.                                                         Events[Eventnum].command = bsrOFF;
  764.                                                         info(0);
  765.                                                 }
  766.                                                 else
  767.                                                         pleasemodule();
  768.                                                 break;
  769.                                         }
  770.  
  771.                                         if (Intuimsg == (APTR)&gadDIMUP)  { /* "BRIGHTER" */
  772.                                                 if (Eventnum)  {
  773.                                                         ++Changed;
  774.                                                         Events[Eventnum].command = bsrDIM;
  775.                                                         n = --Events[Eventnum].dimness;
  776.                                                                 if (n < 0)
  777.                                                                         Events[Eventnum].dimness = 0;
  778.                                                         info(0);
  779.                                                 }
  780.                                                 else
  781.                                                         pleasemodule();
  782.                                                 break;
  783.                                         }
  784.  
  785.                                         if (Intuimsg == (APTR)&gadDIMDN)  { /* "DIMMER" */
  786.                                                 if (Eventnum)  {
  787.                                                         Events[Eventnum].command = bsrDIM;
  788.                                                         ++Changed;
  789.                                                         n = ++Events[Eventnum].dimness;
  790.                                                                 if (n >= 16 )
  791.                                                                         Events[Eventnum].dimness = 15;
  792.                                                         info(0);
  793.                                                 }
  794.                                                 else
  795.                                                         pleasemodule();
  796.                                                 break;
  797.                                         }
  798.  
  799.  
  800.                                         if (Intuimsg == (APTR)&gadNEWFILE)  { /* "NEW FILE" */
  801.                                                 if (Changed)
  802.                                                         savedata();
  803.                                                 goto top;
  804.                                         }
  805.  
  806.                                         if (Intuimsg == (APTR)&gadSECURITY)  { /* "SECURITY" */
  807.                                                 if (Eventnum == 0)
  808.                                                         pleasemodule();
  809.                                                 else  {
  810.                                                         Events[Eventnum].flags ^= SECURITY;
  811.                                                         setdategadgets();
  812.                                                         ++Changed;
  813.                                                 }
  814.                                                 break;
  815.                                         }
  816.  
  817.                                         if (Eventnum)  {
  818.                                                 /* If there is a selected event, and if the
  819.                                                    user clicks on a day-name, then that day's
  820.                                                    enable bit is toggled in the event data. */
  821.  
  822.                                                 if (Intuimsg == (APTR)&gadMON)                          j =  1;
  823.                                                         else if (Intuimsg == (APTR)&gadTUES)    j =  2;
  824.                                                         else if (Intuimsg == (APTR)&gadWED)             j =  4;
  825.                                                         else if (Intuimsg == (APTR)&gadTHURS)   j =  8;
  826.                                                         else if (Intuimsg == (APTR)&gadFRI)             j = 16;
  827.                                                         else if (Intuimsg == (APTR)&gadSAT)             j = 32;
  828.                                                         else if (Intuimsg == (APTR)&gadSUN)             j = 64;
  829.                                                         else if (Intuimsg == (APTR)&gadWEEKDAYS)j = 0x1F;
  830.                                                         else if (Intuimsg == (APTR)&gadWEEKEND) j = 0x60;
  831.                                                         else j = 0;
  832.  
  833.                                                 if (j)  {
  834.                                                         RenderOneEvent(-1, Eventnum, NULL);
  835.                                                         i = Events[Eventnum].days;
  836.                                                         if ((i ^= j) != 0) {    /* preclude NO days */
  837.                                                                 Events[Eventnum].days = i;
  838.                                                                 info(0);
  839.                                                                 setdategadgets();
  840.                                                                 RenderOneEvent(RED, Eventnum, NULL);
  841.                                                                 ++Changed;
  842.                                                         }
  843.                                                         else
  844.                                                                 yesyes("That would select NO Days!");
  845.                                                 }
  846.                                         }
  847.                                         break;
  848.  
  849.  
  850.  
  851.                         case CLOSEWINDOW:                       /* the system CLOSE WINDOW gadget */
  852. signoff:
  853.                                         if (Changed)
  854.                                                 savedata();
  855.                                         cleanup();
  856.                                         exit(0);
  857.  
  858.                         case MOUSEBUTTONS:                      /* Not a gadget, clicked on a pixel */
  859.                                         if (code == SELECTDOWN)  {  /* Button pressed down? */
  860.                                                 if (mousey <= DevAreaY && mousey >= Yorg)  {
  861.                                                         /* clicked in top half, where events are drawn  */
  862.  
  863.                                                         if (Eventnum)   /* undraw RED one, if any */
  864.                                                                 RenderOneEvent(0, Eventnum, devicenames[Devnum]);
  865.  
  866.                                                         i = Devnum;     /* previous device # */
  867.                                                         Devnum = (mousey-Yorg) / barsize; /* new device no. */
  868.  
  869.                                                         if (mousex > xmax)  {  /* clicked on right side? */
  870.                                                                 if (i == Devnum)
  871.                                                                         Eventnum = successor(Eventnum);
  872.                                                                 else
  873.                                                                         Eventnum = listhead(Devnum);
  874.                                                                 info(0);
  875.                                                                 setdategadgets();
  876.                                                                 RenderOneEvent(RED,Eventnum,devicenames[Devnum]);
  877.                                                         }
  878.                                                         else if (mousey >= Yorg)  {
  879.  
  880.                                                                 /* clicked on left side...on an event line? */
  881.                                                                 Eventnum = listhead(Devnum);
  882.  
  883.                                                                 while (Eventnum)
  884.                                                                         if (mousex >= Events[Eventnum].xstart &&
  885.                                                                                   mousex <= Events[Eventnum].xstop )
  886.                                                                                 break;
  887.                                                                         else
  888.                                                                                 Eventnum = Events[Eventnum].link;
  889.  
  890.                                                                 if (Eventnum == 0)
  891.                                                                         AddEvent();     /* another event this dev */
  892.                                                                 info(0);
  893.                                                                 setdategadgets();
  894.                                                                 RenderOneEvent(RED,Eventnum,devicenames[Devnum]);
  895.                                                         }
  896.                                                 }
  897.                                         }
  898.                                         break;
  899.  
  900.                         default:
  901.                                 if (Eventnum)  {
  902.                                         RenderOneEvent(0, Eventnum, devicenames[Devnum]);
  903.                                         setdategadgets();
  904.                                         info(0);
  905.                                         Eventnum = Devnum = 0;
  906.                                         break;
  907.                                 }
  908.  
  909.                 } /* switch */
  910.  
  911.  
  912.         } /* for */
  913.  
  914.         return(0);
  915. }
  916.  
  917. /* ================================================================= */
  918.  
  919. validspan(event, startx, stopx)
  920.         register int event, startx, stopx;
  921. {
  922.  
  923.         register int n;
  924.         int dev;
  925.  
  926.  
  927.         if (startx > stopx)
  928.                 return(-1);
  929.  
  930.         if (stopx > xmax)
  931.                 return(-3);
  932.  
  933.         if (startx <= 0)
  934.                 return(-5);
  935.  
  936.         n = Events[event].link;         /* n = next event, if any */
  937.         if (n)
  938.                 if (stopx >= Events[n].xstart)
  939.                         return(-7);
  940.  
  941.         dev = Events[event].devicecode;         /* find preceeding event, if any */
  942.         n = devicelist[dev];
  943.  
  944.         while (n)  {
  945.                 if (Events[n].link == event)  {
  946.                         if (startx <= Events[n].xstop)
  947.                                 return(-11);    /* bumped into left-hand neighbor */
  948.                         break;                          /* it's OK */
  949.                 }
  950.                 n = Events[n].link;
  951.         }
  952.         return(0);
  953. }
  954.  
  955.  
  956.  
  957. /* ================================================================= */
  958.  
  959.  
  960. pleasemodule()
  961. {
  962.         yesyes("Please Click On An Event or a Module Number.");
  963.         return(0);
  964. }
  965.  
  966.  
  967. /* ================================================================= */
  968.  
  969. /** This table converts unit number 1..8 or 9..16
  970.         to a bit flag, per X10 manual. Index with (1 <= n <= 8)         */
  971. SHORT unitcode[] =  {
  972.         0, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x1
  973.         };
  974.  
  975.  
  976. download()
  977. {
  978.         register int unit, i, n, t;
  979.         int dev, eventnum;
  980.         register char *p;
  981.  
  982.         if (Eventnum)
  983.                 RenderOneEvent(0, Eventnum, devicenames[Devnum]);       /* unRED display */
  984.         Eventnum = Devnum = 0;
  985.         info(0);
  986.  
  987.         if (Changed)
  988.                 savedata();
  989.  
  990.         X10cmd[17] = 0;                 /* base housecode & reset interface */
  991.         X10cmd[18] = Housecodes[BaseHouseCode];         /* housecode */
  992.         x10out(&X10cmd[1],18);
  993.         if (getack() < 0)
  994.                 return(-1);
  995.  
  996.         eventnum = 0;
  997.         purgex10();                             /* purge pending input data */
  998.  
  999.         for (dev = 1; dev <= deviceMax; ++dev)  {       /* usually, 32 devices */
  1000.  
  1001.                 n = devicelist[dev];            /* event number 1..128 */
  1002.  
  1003.                 if (n == 0)
  1004.                         continue;                               /* skip all this code for unused dev's */
  1005.  
  1006.                 p = &devicenames[dev][0];
  1007.                 X10cmd[17] = 3;                 /* event/graphics download */
  1008.  
  1009.                 for (i = 0; i <= 7; ++i)  {
  1010.                         t = ((dev-1) * 8) + i;  /* graphics object # 0..256 */
  1011.                         X10cmd[18] = t << 1;
  1012.                         X10cmd[19] = (t >> 7) + 4;      /* see page 25 of X10 manual */
  1013.                         if (*p < 0x20 || *p > 0x7f)
  1014.                                 X10cmd[20] = 0x20;
  1015.                         else
  1016.                                 X10cmd[20] = *p;
  1017.                         X10cmd[21] = *++p;
  1018.                         ++p;
  1019.  
  1020. /*                      if (verbose)
  1021.                                 printf("dnload dev %d's dev name; cmd=%02X %02X %02X %02X %02X\n",
  1022.                                 dev, X10cmd[17],X10cmd[18],X10cmd[19],X10cmd[20],X10cmd[21]);
  1023. */                      x10out(&X10cmd[1], 22);         /* download 2 chars of devicename */
  1024.                         /* The controller doesn't ACK this command */
  1025.                 }
  1026.  
  1027.                 unit = ((dev-1) % 16) + 1;
  1028.                 t = (dev-1) / 16;
  1029.                 X10cmd[26] = Housecodes[t + BaseHouseCode];
  1030.  
  1031.                 if (unit <= 8)
  1032.                         X10cmd[24] = unitcode[dev];
  1033.                 else
  1034.                         X10cmd[24] = 0;
  1035.                 if (unit > 8)
  1036.                         X10cmd[25] = unitcode[unit - 8];
  1037.                 else
  1038.                         X10cmd[25] = 0;
  1039.  
  1040.                 /*** do all events for the current device */
  1041.                 while (n) {
  1042.                         sprintf(scratchbuf, "Sending Device #%d, event #%d", dev, n);
  1043.                         appease(scratchbuf);
  1044.  
  1045.                         /** Compose command for start of event */
  1046.                         ++eventnum;
  1047.                         X10cmd[18] = eventnum << 3;     /* see pg 21 of X10 manual */
  1048.                         X10cmd[19] = eventnum >> 5;     /* n must be <= 128 */
  1049.                         if (Events[n].flags & SECURITY)
  1050.                                 X10cmd[20] = 9;                         /* normal vs. security mode */
  1051.                         else
  1052.                                 X10cmd[20] = 8;
  1053.  
  1054.                         X10cmd[21] = Events[n].days;
  1055.                         t = Events[n].xstart * minutesK;
  1056.                         X10cmd[22] = t / 60;            /* hours */
  1057.                         X10cmd[23] = t % 60;            /* minutes */
  1058.                         X10cmd[27] = (Events[n].dimness << 4) | Events[n].command;
  1059.                         t = 0;
  1060.                         for (i = 20; i <= 27; ++i)  { /* compute checksum per X10 manual */
  1061.                                 t += X10cmd[i];
  1062.                         }
  1063.                         X10cmd[28] = t;
  1064.                         x10out(&X10cmd[1], 28);         /* download this activity */
  1065.                         if (getack() < 0)
  1066.                                 return(-1);
  1067.  
  1068.                         /*** If event just sent is not an OFF command then
  1069.                                  create and send an OFF command to match the command
  1070.                                  just downloaded. This is because OFF events are not
  1071.                                  stored herein, unless they are special;  explicitly defined.
  1072.                         ***/
  1073.  
  1074.                         if ( (Events[n].command != bsrOFF) )  {
  1075. /*** 6/20/91 ***/
  1076. #if 0
  1077.                             printf("dev=%d n=%d Events[n].xstop=%d Events[Events[n].link].xstart=%d\n",
  1078.                                     dev, n, Events[n].xstop, Events[Events[n].link].xstart);
  1079. #if 1
  1080.                                 if (Events[n].link &&
  1081.                                         ((Events[Events[n].link].xstart -
  1082.                                           Events[n].xstop) == 1))
  1083.                                     goto ADJACENCY;
  1084. #endif
  1085. #endif
  1086.                                 ++eventnum;
  1087.                                 X10cmd[18] = eventnum << 3;
  1088.                                 X10cmd[19] = eventnum >> 5;
  1089.                                 t = Events[n].xstop * minutesK;
  1090.                                 X10cmd[22] = t / 60;            /* hours */
  1091.                                 X10cmd[23] = t % 60;            /* minutes */
  1092.                                 X10cmd[27] = bsrOFF;
  1093.  
  1094.                                 t = 0;
  1095.                                 for (i = 20; i <= 27; ++i)  /* compute checksum per X10 manual */
  1096.                                         t += X10cmd[i];
  1097.  
  1098.                                 X10cmd[28] = t;
  1099.                                 x10out(&X10cmd[1], 28);         /* download event # n-1 */
  1100.                                 if (getack() < 0)
  1101.                                         return(-1);
  1102.                         }
  1103. ADJACENCY:
  1104.                         n = Events[n].link;                     /* next event, this device */
  1105.                 } /* while (linked list for dev N) */
  1106.         }
  1107.         return(0);
  1108. }
  1109.  
  1110.  
  1111. /* ======== Erase all stored events ============ */
  1112. purge()
  1113. {
  1114.         register int i;
  1115.  
  1116.         Eventnum = Devnum = Changed = 0;
  1117.  
  1118.         for (i = 0; i <= deviceMax; ++i)  {
  1119.                 devicenames[i][0] = '\0';
  1120.                 devicelist[i] = 0;
  1121.         }
  1122.  
  1123.         for (i = 0; i <= recordlimit; ++i)
  1124.                 Events[i].link = Events[i].devicecode = 0;
  1125.  
  1126.         return(0);
  1127. }
  1128.  
  1129.  
  1130. /* ======== Retrieve Event Data & Dev. Names From X10 Box ================= */
  1131.  
  1132. upload()
  1133. {
  1134.         register int i, n, t;
  1135.         int dev = 0, eventnum = 1, x10counter = 0;
  1136.         int prevcmd = -1, prevdev = -1, thiscmd, thisdev, x10byte, icon;
  1137.         UBYTE *p, x10reply[32];
  1138.  
  1139.         appease("Requesting Data from CP290");
  1140.  
  1141.         purge();                        /* purge all events */
  1142.         TimeGraticule();
  1143.         info(0);
  1144.  
  1145.         purgex10();                     /* scrub pending serial input */
  1146.         X10cmd[17] = 5;         /* request events, see page 31 of X10 manual */
  1147.         x10out(&X10cmd[1], 17);         /* event # n-1 */
  1148.         Delay(50);
  1149.  
  1150. /*** read and discard leading sync and the status byte */
  1151.  
  1152.         do {
  1153.                 if ( (n = x10inbyte()) < 0) {
  1154.                         notresponding(n);
  1155.                         return(-1);
  1156.                 }
  1157.         }
  1158.         while (n == 0xff);      /* "status" is first byte other than 0xff */
  1159.  
  1160.  
  1161. /*** Read all uploaded events */
  1162.  
  1163.         while (x10counter++ < 128)  {
  1164.                 if ((n = x10inbyte()) < 0)
  1165.                         return(-2);
  1166.                 n &= 0xff;
  1167.  
  1168.                 if (n != 0xff)  {                                       /* active event? */
  1169.                         x10reply[1] = n;                                /* dupe. 1st byte */
  1170.                         for (i = 2; i <= 8; ++i)  {             /* read an event */
  1171.                                 if ((n = x10inbyte()) < 0)
  1172.                                         return(-3);
  1173.                                 x10reply[i] = n & 0xff;
  1174.                         }
  1175.  
  1176.                         sprintf(scratchbuf, "Receiving event #%d", eventnum);
  1177.                         appease(scratchbuf);
  1178.  
  1179.  
  1180.                         t = (x10reply[5] << 8) + x10reply[6];   /* bit map of unit codes */
  1181.                         dev = 16;
  1182.                         while ((t & 1) == 0) {
  1183.                                 --dev;
  1184.                                 if ((t >>= 1) == 0)
  1185.                                         return(-4);
  1186.                         }
  1187.  
  1188.                         n = x10reply[7];                                        /* house code */
  1189.                         for (i = 1; i <= 16; ++i)
  1190.                                 if (n == (int)Housecodes[i])
  1191.                                         break;  /* i = 1 If housecode == 0x60, etc. */
  1192.                         Events[eventnum].devicecode = dev + ((i-1) * 16);       /* 1..32 */
  1193.  
  1194.                         if ((x10reply[1] & 0x0F) == 9)
  1195.                                 Events[eventnum].flags |= SECURITY;
  1196.                         else
  1197.                                 Events[eventnum].flags &= (~SECURITY);
  1198.  
  1199.                         Events[eventnum].dimness = (x10reply[8] >> 4) & 0x0F;
  1200.                         Events[eventnum].command = (x10reply[8] & 0x0F);
  1201.                         Events[eventnum].days = x10reply[2];
  1202.                         n = ((x10reply[3] * 60) + x10reply[4]) / minutesK;
  1203.                         if (n > xmax)
  1204.                                 return(-5);
  1205.                         Events[eventnum].xstart = Events[eventnum].xstop = n;
  1206.  
  1207.                         thisdev = Events[eventnum].devicecode;
  1208.                         thiscmd = Events[eventnum].command;
  1209.  
  1210.                         /*** Throw away this uploaded event if
  1211.                                 1) It is for same device as previous one, and
  1212.                                 2) the previous event was NOT an OFF command, and
  1213.                                 3) the current event IS an OFF event.
  1214.                                 This discards the OFF event paired with some earlier event.
  1215.                         ***/
  1216.  
  1217.                         if (        (prevdev == thisdev)        /* use OFF part of last event */
  1218.                                          && (prevcmd != bsrOFF)
  1219.                                          && (thiscmd == bsrOFF)   )
  1220.                                 Events[eventnum -1].xstop = Events[eventnum].xstart;
  1221.                         else  {                                                         /* create new event */
  1222.                                 Events[eventnum].link = 0;
  1223.                                 if ((n = devicelist[dev]) == 0)
  1224.                                         devicelist[dev] = eventnum++;           /* make head of list */
  1225.                                 else  {
  1226.                                         while (Events[n].link)
  1227.                                                 n = Events[n].link;
  1228.                                         Events[n].link = eventnum++;    /* make tail of list */
  1229.                                 }
  1230.                         }
  1231.                         prevdev = thisdev;
  1232.                         prevcmd = thiscmd;
  1233.                 }
  1234.         }
  1235.  
  1236.         purgex10();                     /* scrub pending serial input */
  1237.         X10cmd[17] = 6;         /* request graphics data */
  1238.         x10out(&X10cmd[1], 17);
  1239.         while (x10inbyte() == 0xff)                     /* discard sync & status */
  1240.                 ;
  1241.  
  1242.         for (icon = 1; icon <= 256; ++icon) {
  1243.  
  1244.                 if (((icon-1) & 7) == 0)  {
  1245.                         dev = (icon / 8) + 1;
  1246.                         sprintf(scratchbuf, "Receiving device name #%d", dev);
  1247.                         appease(scratchbuf);
  1248.                         p = &devicenames[dev][0];
  1249.                 }
  1250.                 if ((x10byte = x10inbyte()) < 0)
  1251.                         return(x10byte);
  1252.                 if (x10byte != 0xff)  {                         /* vacant space? */
  1253.                         *p++ = x10byte;                                 /* assign 2 bytes */
  1254.                         *p++ = (char) x10inbyte();
  1255.                 }
  1256.         }
  1257.  
  1258.         for (dev = 1; dev <= deviceMax; ++dev)          /* truncate */
  1259.                 devicenames[dev][DEVNAMELEN-1] = '\0';
  1260.  
  1261.         RenderAllEvents();
  1262.         info(0);
  1263.         setdategadgets();
  1264.         return(0);
  1265. }
  1266.  
  1267. #if 0
  1268. /* ================================================================= */
  1269.  
  1270. sunset()
  1271. {
  1272.         register int month, min, hhmm24;
  1273.         char clockinfo[8];
  1274.  
  1275.         getclk(clockinfo);                              /* See Lattice 4.0 page F110 */
  1276.         month = (int)clockinfo[2];
  1277.         hhmm24 = sunsettable[month-1] + (dsmonths[month] * 100);
  1278.  
  1279.         min = (hhmm24 / 100) * 60;      /* hour time minutes per hour */
  1280.         min += hhmm24 % 60;                     /* minutes part */
  1281.  
  1282.         return(min / minutesK);         /* time as an offset in pixels along X */
  1283.  
  1284. }
  1285. #endif
  1286.  
  1287.  
  1288. /* ================================================================= */
  1289.  
  1290. int
  1291. x10command()
  1292. {
  1293.         register int n, m;
  1294.  
  1295.         X10cmd[17] = 1;
  1296.         X10cmd[18] = Events[Eventnum].command;
  1297.         X10cmd[18] |= (Events[Eventnum].dimness << 4);
  1298.         n = (Events[Eventnum].devicecode -1) / 16;
  1299.         X10cmd[19] = Housecodes[n+1];
  1300.  
  1301.         if ((n = Events[Eventnum].devicecode) == 0)  /* device 1..32 */
  1302.                 return(-2);  /* should never be 0! */
  1303.         n &= 15;   /* n = device 1..16 */
  1304.         if (n == 0)
  1305.                 n = 16;
  1306.  
  1307.         m = 0x8000;     /* see page 12 of X10 manual for bit alignment */
  1308.         while (--n)
  1309.                 m >>= 1;
  1310.         X10cmd[20] = m & 0xff;
  1311.         X10cmd[21] = m >> 8;
  1312.         X10cmd[22] = X10cmd[18] + X10cmd[19] + X10cmd[20] + X10cmd[21];
  1313.  
  1314.         appease("Sending to CP290");
  1315.         x10out(&X10cmd[1], 22);
  1316.         n = getack();
  1317.         if (n < 0)
  1318.                 return(0);
  1319.         return(0);
  1320. }
  1321.  
  1322.  
  1323. /* ================================================================= */
  1324. int
  1325. notresponding(err)
  1326.         int err;
  1327. {
  1328.         char prompt[100];
  1329.  
  1330.         sprintf(prompt, " The X10 CP290 Controller Is Not Responding! (%d) ", err);
  1331.  
  1332.         return(yesyes(prompt));
  1333. }
  1334.  
  1335. /* ================================================================= */
  1336. int
  1337. getack()                /* read the ACK response to a command */
  1338. {
  1339.         register int x10reply;
  1340.  
  1341.         do
  1342.                 if ((x10reply = x10inbyte()) < 0)  {
  1343.                         notresponding(x10reply);
  1344.                         return(x10reply);
  1345.                 }
  1346.         while (x10reply == 0xff);               /* discard syncs */
  1347.         return(x10reply);                               /* response should be 0 or 1 */
  1348. }
  1349.  
  1350.  
  1351. /* ================================================================= */
  1352. int
  1353. x10date()
  1354. {
  1355.         register int n, x10byte;
  1356.         char x10info[8], clockinfo[8], *dayis, basecode;
  1357.  
  1358.  
  1359. dateagain:
  1360.         purgex10();
  1361.         X10cmd[17] = 4;                                 /* Request date */
  1362.         x10out(&X10cmd[1], 17);
  1363.  
  1364.         do  {
  1365.                 x10byte = x10inbyte();
  1366.                 if (x10byte < 0)  {
  1367.                         notresponding(x10byte);
  1368.                         return(x10byte);
  1369.                 }
  1370.         }
  1371.         while (x10byte & 0x80);                 /* strip leading syncs */
  1372.  
  1373.         x10info[0] = x10byte;                   /* status byte */
  1374.  
  1375.         for (n = 1; n <= 5; ++n)  {
  1376.                 if ((x10byte = x10inbyte()) < 0)  {
  1377.                         notresponding(x10byte);
  1378.                         return(x10byte);
  1379.                 }
  1380.                 x10info[n] = x10byte;
  1381.         }
  1382.  
  1383.         switch ((int)x10info[3])  {
  1384.                 case 0x40:      dayis = "Sun";
  1385.                                         break;
  1386.                 case 0x20:      dayis = "Sat";
  1387.                                         break;
  1388.                 case 0x10:      dayis = "Fri";
  1389.                                         break;
  1390.                 case 0x08:      dayis = "Thu";
  1391.                                         break;
  1392.                 case 0x04:      dayis = "Wed";
  1393.                                         break;
  1394.                 case 0x02:      dayis = "Tue";
  1395.                                         break;
  1396.                 case 0x01:      dayis = "Mon";
  1397.                                         break;
  1398.                 default:        dayis = "???";
  1399.                                         break;
  1400.         }
  1401.         switch ((int)x10info[4])  {
  1402.                 case 0x60:      basecode = 'A';
  1403.                                         break;
  1404.                 case 0xE0:      basecode = 'B';
  1405.                                         break;
  1406.                 case 0x20:      basecode = 'C';
  1407.                                         break;
  1408.                 case 0xA0:      basecode = 'D';
  1409.                                         break;
  1410.                 case 0x10:      basecode = 'E';
  1411.                                         break;
  1412.                 case 0x90:      basecode = 'F';
  1413.                                         break;
  1414.                 case 0x50:      basecode = 'G';
  1415.                                         break;
  1416.                 case 0xD0:      basecode = 'H';
  1417.                                         break;
  1418.                 case 0x70:      basecode = 'I';
  1419.                                         break;
  1420.                 case 0xF0:      basecode = 'J';
  1421.                                         break;
  1422.                 case 0x30:      basecode = 'K';
  1423.                                         break;
  1424.                 case 0xB0:      basecode = 'L';
  1425.                                         break;
  1426.                 case 0x00:      basecode = 'M';
  1427.                                         break;
  1428.                 case 0x80:      basecode = 'N';
  1429.                                         break;
  1430.                 case 0x40:      basecode = 'O';
  1431.                                         break;
  1432.                 case 0xC0:      basecode = 'P';
  1433.                                         break;
  1434.                 default:        basecode = '?';
  1435.                                         break;
  1436.         }
  1437.  
  1438.         sprintf(textbuf, "DATE: %s, %d:%02d (base-code:%c) - Change to Amiga's DATE?",
  1439.                 dayis, x10info[2], x10info[1], basecode);
  1440.         if (yesno(textbuf))  {
  1441.                 getclk(clockinfo);      /* See Lattice 4.0 page F110 */
  1442.                 X10cmd[17] = 2;         /* set clock */
  1443.                 X10cmd[18] = clockinfo[5];      /* min */
  1444.                 X10cmd[19] = clockinfo[4];      /* hr */
  1445.                 switch ((int)clockinfo[0])  {
  1446.                         case 0: n = 0x40;       /* Sunday */
  1447.                                         break;
  1448.                         case 1: n = 0x01;       /* Mon */
  1449.                                         break;
  1450.                         case 2: n = 0x02;       /* Tue */
  1451.                                         break;
  1452.                         case 3: n = 0x04;       /* Wed */
  1453.                                         break;
  1454.                         case 4: n = 0x08;       /* Thu */
  1455.                                         break;
  1456.                         case 5: n = 0x10;       /* Fri */
  1457.                                         break;
  1458.                         case 6: n = 0x20;       /* Sat */
  1459.                                         break;
  1460.                 }
  1461.                 X10cmd[20] = n;
  1462.                 X10cmd[21] = X10cmd[18] + X10cmd[19] + X10cmd[20];      /* chksum */
  1463.                 x10out(&X10cmd[1], 21);
  1464.                 getack();
  1465.                 goto dateagain;
  1466.         }
  1467.         return(0);
  1468. }
  1469.  
  1470.  
  1471.  
  1472. /* ================================================================= */
  1473.  
  1474. int
  1475. yesno(p)
  1476.         char *p;
  1477. {
  1478.         register int w, result, save1;
  1479.  
  1480.  
  1481.         save1 = colortable[WHITE];
  1482.         colortable[WHITE] = DEEPBLUE;
  1483.         LoadRGB4(ViewPortAddress(window), &colortable[0], 16);
  1484.  
  1485.         ynmessage.IText = p;
  1486.         w = (strlen(p) * 8) + 50;
  1487.         if (w < 200)
  1488.                 w = 200;
  1489.  
  1490.         if (yesyesflag == 0)
  1491.                 result = AutoRequest(window, &ynmessage, &yesmsg, &nomsg,
  1492.                         0, 0, w, 64);
  1493.         else
  1494.                 result = AutoRequest(window, &ynmessage, &yesmsg, &yesmsg,
  1495.                         0, 0, w, 64);
  1496.  
  1497.         colortable[WHITE] = save1;
  1498.         LoadRGB4(ViewPortAddress(window), &colortable[0], 16);
  1499.         return(result);
  1500. }
  1501.  
  1502. /* ================================================================= */
  1503.  
  1504. int
  1505. yesyes(p)
  1506.         char *p;
  1507. {
  1508.         register int result;
  1509.  
  1510.         ++yesyesflag;
  1511.         result = yesno(p);
  1512.         yesyesflag = 0;
  1513.         return(result);
  1514. }
  1515.  
  1516. /* ================================================================= */
  1517. int
  1518. purgex10()
  1519. {
  1520.         register int i;
  1521.  
  1522.         for (i = 1; i <= 2; ++i)  {
  1523.                 Delay(10);
  1524.                 while (x10inbyte() >= 0)
  1525.                         ;               /* purge pending data */
  1526.         }
  1527.         return(0);
  1528. }
  1529.  
  1530. /* ================================================================= */
  1531.  
  1532. int
  1533. x10out(buf, count)              /* send a buffer to the X10 CP290 Interface Unit */
  1534.         char *buf;
  1535.         int count;
  1536. {
  1537.         register int n;
  1538.         register char *p = buf;
  1539.         char emsg[80];
  1540.  
  1541.         IORser.IOSer.io_Command = CMD_WRITE;
  1542.  
  1543.         for (n = count; n > 0; --n)  {
  1544.                 IORser.IOSer.io_Data = (APTR)p++;
  1545.                 IORser.IOSer.io_Length = 1;
  1546.                 if (error = DoIO(&IORser))  {
  1547.                         sprintf(emsg, "Serial Port WRITE error %d", error)
  1548.                         yesyes(emsg);
  1549.                         return(error);
  1550.                 }
  1551.                 Delay(1);       /* X10 says delay between bytes (this is 1/50 of a sec) */
  1552.         }
  1553.         return(0);
  1554. }
  1555.  
  1556. /* ================================================================= */
  1557.  
  1558.  
  1559. static char onech;
  1560.  
  1561. int
  1562. x10inbyte()                     /* returns < 0 if error, else 8 bit reply data */
  1563. {
  1564.         register int n, timeout = 5;
  1565.         char prompt[100];
  1566.  
  1567. reread:
  1568.         chkabort();
  1569.         IORser.IOSer.io_Command = SDCMD_QUERY;  /* See if data is available */
  1570.         if ((n = DoIO(&IORser)) != 0)  {
  1571.                 sprintf(prompt, " Serial Port Read Error: %d ", n);
  1572.                 yesyes(prompt);
  1573.                 return(-1);
  1574.         }
  1575.         if (IORser.IOSer.io_Actual != 0)  {
  1576.                 IORser.IOSer.io_Command = CMD_READ;
  1577.                 IORser.IOSer.io_Length = 1;
  1578.                 IORser.IOSer.io_Data = (APTR)&onech;
  1579.                 if (DoIO(&IORser) != 0)
  1580.                         return(-2);                                             /* return if I/O error */
  1581.         }
  1582.         else  {
  1583.                 Delay(5);       /* No data avail now, so delay and retry */
  1584.                 if (--timeout > 0)
  1585.                         goto reread;
  1586.                 return(-3);
  1587.         }
  1588.         n = onech & 255;
  1589.         if (verbose)
  1590.                 printf("$%02X ",n);
  1591.         return(n);
  1592. }
  1593.  
  1594. /* ================================================================= */
  1595.  
  1596.  
  1597. int
  1598. standby(on)             /* prompt user to wait before taking next action */
  1599.         int on;
  1600. {
  1601.  
  1602.         if (on)  {
  1603.                 standbywindow.Screen = screen;
  1604.                 if ((sbwindow = OpenWindow(&standbywindow)) == NULL)
  1605.                         return(-1);
  1606.                 sbRport = sbwindow->RPort;
  1607.         }
  1608.         else if (sbwindow != NULL)  {
  1609.                 CloseWindow(sbwindow);
  1610.                 sbwindow = NULL;
  1611.                 sbRport  = NULL;
  1612.         }
  1613.         return(0);
  1614. }
  1615.  
  1616.  
  1617. /* ================================================================= */
  1618. #define APPEASEMSGX 200
  1619. #define APPEASEMSGY  50
  1620.  
  1621. appease(msg)
  1622.         char *msg;
  1623. {
  1624.         char buf[80];
  1625.  
  1626.         if (sbRport == NULL)
  1627.                 return(-1);
  1628.  
  1629.         SetAPen(sbRport, GREY8);
  1630.         intuitext.IText = buf;
  1631.         intuitext.FrontPen = GOLD;
  1632.         intuitext.DrawMode = JAM2;
  1633.  
  1634.  
  1635.         sprintf(buf, "  %-40s  ", msg);
  1636.         PrintIText(sbRport, &intuitext, APPEASEMSGX, APPEASEMSGY);
  1637.  
  1638.         return(0);
  1639.  
  1640. }
  1641.  
  1642. /* ================================================================= */
  1643.  
  1644. int
  1645. setname()
  1646. {
  1647.  
  1648.         nameinfo.Buffer = (UBYTE *)&devicenames[0];
  1649.     strcpy(nameinfo.Buffer, &devicenames[Devnum]);
  1650.         nameinfo.MaxChars = DEVNAMELEN;
  1651.  
  1652.         if (requeststring(" Name of Appliance? "))
  1653.                 return(-1);
  1654.         if (strlen(nameinfo.Buffer) == 0)
  1655.                 return(0);
  1656.  
  1657.         RenderOneEvent(-1, devicelist[Devnum], devicenames[Devnum]); /* erase old string */
  1658.         strcpy(&devicenames[Devnum], &devicenames[0]);
  1659.         RenderOneEvent(RED, Eventnum, devicenames[Devnum]);
  1660.         ++Changed;
  1661.         return(0);
  1662. }
  1663.  
  1664. /* ================================================================= */
  1665.  
  1666. int
  1667. setbase()
  1668. {
  1669.         char housechar[2];
  1670.  
  1671.         housechar[0] = BaseHouseCode-1 + 'A';
  1672.         housechar[1] = '\0';
  1673.  
  1674.         nameinfo.Buffer = (UBYTE *)&housechar;
  1675.     nameinfo.MaxChars = 2;
  1676.         nameinfo.BufferPos = 1;
  1677.         nameinfo.Buffer[0] = housechar[0];
  1678.  
  1679.         if (requeststring(" Base House Code? "))
  1680.                 return(-1);
  1681.         if (strlen(nameinfo.Buffer) == 0)
  1682.                 return(-1);
  1683.         housechar[0] = toupper(housechar[0]);
  1684.  
  1685.         if (housechar[0] < 'A' || housechar[0] > 'P')
  1686.                 return(-1);
  1687.         BaseHouseCode = 1 + (housechar[0] - 'A');
  1688.         return(0);
  1689. }
  1690.  
  1691.  
  1692. /* ================================================================= */
  1693.  
  1694. int
  1695. requeststring(prompt)
  1696.         char *prompt;
  1697. {
  1698.         register struct Window *window1;
  1699.         register struct MsgPort *intuiport;
  1700.         register struct IntuiMessage *message;
  1701.         register int signalflag;
  1702.         APTR intuimsg;
  1703.         int n, class, code;
  1704.  
  1705.         gadNAMEmsg.IText = prompt;
  1706.         nw1.Screen = screen;
  1707.         n = (strlen(prompt) * 10);
  1708.         if (n < nw1X)
  1709.                 n = nw1X;
  1710.         nw1.Width = n+16;
  1711.  
  1712.         nameinfo.BufferPos = strlen(nameinfo.Buffer);
  1713.  
  1714.         if ((window1 = OpenWindow(&nw1)) != NULL)  {
  1715.                 ActivateGadget(&gadNAME, window1, NULL);
  1716.                 intuiport = window1->UserPort;
  1717.                 signalflag = 1 << window1->UserPort->mp_SigBit;
  1718.                 Wait(signalflag);
  1719.                 message = GetMsg(intuiport);
  1720.  
  1721.                 intuimsg = (APTR)message->IAddress; /* for gadgets, points to gadget*/
  1722.  
  1723.                 class  = message->Class;
  1724.                 code   = message->Code;
  1725.                 ReplyMsg(message);
  1726.                 CloseWindow(window1);
  1727.  
  1728.                 if (class == CLOSEWINDOW)
  1729.                         return(-1);
  1730.         }
  1731.         return(0);
  1732. }
  1733.  
  1734.  
  1735. /* ================================================================= */
  1736.  
  1737. int
  1738. getfilename(prompt)
  1739. /* return: 0=have name; 1=blank name; 2=closed window; -1=abort requested */
  1740.         char *prompt;
  1741. {
  1742.  
  1743.         nameinfo.Buffer = scratchbuf;
  1744.     strcpy(nameinfo.Buffer, datafilename);
  1745.         nameinfo.MaxChars = sizeof(datafilename)-1;
  1746.  
  1747.         /* get filename string. if user clicks on window close, ask QUIT? */
  1748.         if (requeststring(prompt))  {
  1749.                 if (yesno("    QUIT?     "))
  1750.                         return(-1);                     /* yes, abort */
  1751.                 else
  1752.                         return(2);                      /* no, don't quit, but don't have a name */
  1753.         }
  1754.  
  1755.         if (strlen(nameinfo.Buffer) == 0)
  1756.                 return(1);                              /* name length bad? */
  1757.  
  1758.         strcpy(datafilename, nameinfo.Buffer);
  1759.         return(0);
  1760. }
  1761.  
  1762. /* ================================================================= */
  1763.  
  1764.  
  1765. int
  1766. savedata()
  1767. {
  1768.         register int dev, n;
  1769.  
  1770.         FILE *datafp = NULL;
  1771.  
  1772.  
  1773.         while (datafp == NULL)  {
  1774.                 if (yesno("Write Screen's Info. Into a File? ") == 0)
  1775.                         return(1);
  1776.  
  1777.                 if ((n = getfilename(" What file? ")) != 0)
  1778.                         return(n);
  1779.  
  1780.                 datafp = fopen(datafilename, "w");
  1781.         }
  1782.  
  1783.  
  1784.         for (dev = 1; dev <= deviceMax; ++dev)  {
  1785.                 n = devicelist[dev];
  1786.                 while (n)  {
  1787.                         fprintf(datafp, "%d,%d,%d,%d,%d,%d,%d\n",
  1788.                                 Events[n].devicecode,
  1789.                                 Events[n].xstart,
  1790.                                 Events[n].xstop,
  1791.                                 Events[n].days,
  1792.                                 Events[n].command,
  1793.                                 Events[n].dimness,
  1794.                                 Events[n].flags);
  1795.  
  1796.                         n = Events[n].link;
  1797.                 }
  1798.         }
  1799.         fprintf(datafp, "0,0,0,0,0,0,0\n");
  1800.  
  1801.         for (dev = 1; dev <= deviceMax; ++dev)
  1802.                 if (devicenames[dev][0] != '\0')
  1803.                         fprintf(datafp, "%d,\"%s\"\n", dev, &devicenames[dev]);
  1804.  
  1805.         fclose(datafp);
  1806.         Changed = 0;
  1807.         return(0);
  1808. }
  1809.  
  1810.  
  1811.  
  1812. /* =================================================================
  1813.         set the displayed day-of-week gadgets (MON, TUE...) to the On/Off
  1814.         state as stored in the currently active event's "days" item.    */
  1815.  
  1816.  
  1817. setdategadgets()
  1818. {
  1819.         register struct Gadget *gad;
  1820.         register int i, daybits;
  1821.  
  1822.  
  1823.         gad = &gadMON;  /* start of gadget list */
  1824.         Daymask = daybits = Events[Eventnum].days;
  1825.  
  1826.         for (i = 1; i <= 64; i *= 2)  {                         /* each day ... */
  1827.                 setonegad(gad, (i & daybits) );
  1828.                 gad = gad->NextGadget;
  1829.         }
  1830.  
  1831.         setonegad(&gadSECURITY, Events[Eventnum].flags & SECURITY);
  1832.         return(0);
  1833. }
  1834.  
  1835.  
  1836. /* ================================================================= */
  1837.  
  1838. setonegad(g, on)
  1839.         struct Gadget *g;
  1840.         int on;
  1841. {
  1842.         register int oldsel, newsel;
  1843.  
  1844.  
  1845.         oldsel = g->Flags;
  1846.         if (on)
  1847.                 newsel = SELECTED;
  1848.         else
  1849.                 newsel = 0;
  1850.  
  1851.         g->Flags |= SELECTED;
  1852.         if (oldsel != newsel)
  1853.                 RefreshGList(g, window, NULL, 1);
  1854.         if (newsel == 0)
  1855.                 g->Flags &= (~SELECTED);
  1856.         return(0);
  1857. }
  1858.  
  1859.  
  1860.  
  1861. /* ================================================================= */
  1862.  
  1863.  
  1864.  
  1865. int
  1866. info(device)            /* display info for a given device code */
  1867.         int device;
  1868. {
  1869.         register int i, m, n;
  1870.         int     x, y,
  1871.                 t1,t2,
  1872.                 cmd,
  1873.                 color,
  1874.                 eventdays,
  1875.                 lnum = infoline+1;
  1876.         char *p, *p1, dimmsg[8];
  1877.  
  1878.         SetBPen(Rport, BLACK);
  1879.  
  1880.         Daymask = Events[Eventnum].days;
  1881.  
  1882.         if (device == 0) {
  1883.                 if (Devnum == 0)
  1884.                         n = 0;
  1885.                 else
  1886.                         n = devicelist[Devnum];  /* use currently selected one */
  1887.         }
  1888.         else
  1889.                 n = devicelist[device];         /* use caller's selected one */
  1890.  
  1891.         /*** Print days of week, with Currently selected day(s) in PENTEXT1 */
  1892.  
  1893.         p = "MTWTFSS";
  1894.         x = infocol * charwidth;
  1895.         y = (lnum -1) * charwidth;
  1896.  
  1897.         for (i = 1; i <= 64; i *= 2)  {
  1898.                 SetAPen(Rport, Daymask & i ? RED : GREEN);
  1899.                 Move(Rport, x, y);
  1900.                 Text(Rport, p++, 1);
  1901.                 x += 8;
  1902.         }
  1903.  
  1904.  
  1905.         /*** Print all events ocurring on the selected day(s) */
  1906.  
  1907.         while (n)  {
  1908.                 p = &textbuf[0];
  1909.                 if (n != Eventnum)
  1910.                         color = GREEN;
  1911.                 else
  1912.                         color = RED;
  1913.                 m = i = 1;
  1914.                 x = infocol * charwidth;
  1915.                 y = ((lnum -1) * charwidth) +1;
  1916.                 eventdays = Events[n].days;
  1917.  
  1918.                 /*** Draw a box for those days of the week
  1919.                         that the event is active */
  1920.  
  1921.                 while (i <= 0x40)  {
  1922.                         if (eventdays & i)
  1923.                                 SetAPen(Rport, DAYCOLOR0 + m - 1);
  1924.                         else
  1925.                                 SetAPen(Rport, BLACK);
  1926.                         RectFill(Rport, x+2, y+2, x+6, y+6);
  1927.                         x += 8;
  1928.                         i *= 2;
  1929.                         ++m;
  1930.                 }
  1931.  
  1932. /***   This code displays the start/stop times for an event */
  1933.  
  1934.                 SetAPen(Rport, color);
  1935.                 t1 = Events[n].xstart * minutesK;
  1936.                 t2 = Events[n].xstop * minutesK;
  1937.                 cmd = Events[n].command;
  1938.  
  1939.                 if (cmd == bsrDIM)
  1940.                         sprintf(p1 = dimmsg, "%2d", 16 - Events[n].dimness);
  1941.                 else
  1942.                         p1 = "   ";
  1943.  
  1944.                 sprintf(p, " %02d:%02d\-%02d:%02d %s%s",
  1945.                         t1 / 60, t1 % 60, t2 / 60, t2 % 60,     bsr[cmd], p1);
  1946.                 Move(Rport, x+8, lnum * charwidth);
  1947.                 Text(Rport,textbuf,strlen(p));
  1948.                 ++lnum;
  1949.                 n = Events[n].link;
  1950.         }
  1951.  
  1952. /*** Erase to end of screen */
  1953.  
  1954.         SetAPen(Rport, BLACK);
  1955.         RectFill(Rport, infocol * charwidth, ((lnum-1) * charwidth) +1, 638, 398);
  1956.         return(0);
  1957. }
  1958.  
  1959. /* ================================================================= */
  1960.  
  1961.  
  1962. int
  1963. DeleteEvent(eventno)
  1964.         int eventno;
  1965. {
  1966.         register int n;
  1967.  
  1968.         if (eventno == 0)  {
  1969.                 pleasemodule();
  1970.                 return(-1);
  1971.         }
  1972.         ++Changed;
  1973.  
  1974.         n = devicelist[Devnum];                                 /* n = head of list */
  1975.         RenderOneEvent(-1, eventno, NULL);              /* erase RED event */
  1976.  
  1977.         if (n == eventno) {
  1978.                 if (Events[eventno].link == 0)  {       /* deleteing sole member of list? */
  1979.                         RenderOneEvent(0, eventno, devicenames[Devnum]); /* unRED dev name */
  1980.                         RenderOneEvent(-1, eventno, NULL); /* erase event */
  1981.                 }
  1982.                 devicelist[Devnum] = Events[eventno].link; /* delete at head of list*/
  1983.         }
  1984.         else  {
  1985.                 while (Events[n].link != eventno)  {    /* find predecessor event */
  1986.                         if (n == 0)  {
  1987.                                 yesyes("Predecessor link error");
  1988.                                 cleanup();
  1989.                                 exit(1);                                                /* corrupted list */
  1990.                         }
  1991.                         n = Events[n].link;
  1992.                 }
  1993.                 Events[n].link = Events[eventno].link;  /* delete within list */
  1994.         }
  1995.         Eventnum = successor(Events[eventno].link);     /* update selected event no. */
  1996.         Events[eventno].devicecode = 0;         /* mark node as unused */
  1997.  
  1998.         if (Eventnum == 0)
  1999.                 Eventnum = listhead(Devnum);
  2000.         if (Eventnum)
  2001.                 RenderOneDevice(Devnum);                        /* put new RED on display */
  2002.         hourlines();
  2003.         return(0);
  2004. }
  2005.  
  2006. /* ================================================================= */
  2007.  
  2008.  
  2009. int
  2010. AddEvent()
  2011. {
  2012.         register int n;
  2013.         int t, predn, xlimit;
  2014.         register int node, x;
  2015.  
  2016.         ++Changed;
  2017.         node = 0;
  2018.  
  2019.         while (Events[++node].devicecode != 0)
  2020.                 ; /* nothing, find an unused node */
  2021.  
  2022.         Events[node].devicecode = Devnum;
  2023.         Events[node].xstart = mousex;
  2024.         Events[node].xstop  = mousex;
  2025.         Events[node].link = 0;
  2026.         Events[node].command = bsrON;
  2027.         Events[node].days = 0x7F;
  2028.         Events[node].flags = 0;
  2029.  
  2030.         Eventnum = node;
  2031.  
  2032.         xlimit = xmax;
  2033.         x = mousex;
  2034.         n = devicelist[Devnum];         /* head of list */
  2035.         predn = 0;
  2036.  
  2037.         while (n)  {            /* find non-overlapping limit for this event */
  2038.                 t = Events[n].xstart;
  2039.                 if (xlimit > t && x < t)
  2040.                         xlimit = t -1;
  2041.                 predn = n;
  2042.                 n = Events[n].link;
  2043.         }
  2044.  
  2045.  
  2046.         if (n == devicelist[Devnum])  {         /* empty list or insert at head of list */
  2047.                 Events[node].link = n;
  2048.                 devicelist[Devnum] = node;
  2049.         }
  2050.         else  {                                                         /* insert within list */
  2051.                 t = Events[predn].link;
  2052.                 Events[predn].link = node;
  2053.                 Events[node].link  = t;
  2054.         }
  2055.  
  2056.         RenderOneEvent(RED, node, devicenames[Devnum]);
  2057.  
  2058.         do  {
  2059.                 if (x - window->MouseX)  {
  2060.                         RenderOneEvent(-1, node, NULL);
  2061.                         x = window->MouseX;
  2062.                         if (x < Events[node].xstart)
  2063.                                 x = Events[node].xstart;
  2064.                         if (x > xlimit)
  2065.                                         x = xlimit;
  2066.                         Events[node].xstop = x;
  2067.                         RenderOneEvent(RED, node, NULL);
  2068.                 }
  2069.                 Delay(1);
  2070.         }
  2071.         while ((SetSignal(0,0) & Signalflag) == 0); /* mouse button UP Message */
  2072.  
  2073.         Wait(Signalflag);
  2074.         Message = GetMsg(Intuiport);
  2075.         ReplyMsg(Message);
  2076.         hourlines();
  2077.         return(0);
  2078. }
  2079.  
  2080. /* ================================================================= */
  2081.  
  2082.  
  2083. int
  2084. RenderAllEvents()
  2085. {
  2086.         register int i;
  2087.  
  2088.         for (i = 1; i <= deviceMax; ++i)
  2089.                 RenderOneDevice(i);
  2090.         info(0);
  2091.         return(0);
  2092. }
  2093.  
  2094.  
  2095.  
  2096.  
  2097. /* ================================================================= */
  2098. int
  2099. RenderOneDevice(devno)
  2100. {
  2101.         register int j, h, e;
  2102.  
  2103.         e = 0;
  2104.         h = j = devicelist[devno];
  2105.  
  2106.  
  2107.         while (j)  {
  2108.                 if (j == Eventnum)
  2109.                         e = j;
  2110.                 RenderOneEvent(0, j, NULL);
  2111.                 j = Events[j].link;
  2112.         }
  2113.  
  2114.         if (e)
  2115.                 RenderOneEvent(RED, e, devicenames[devno]);     /* draw red one last! */
  2116.         else
  2117.                 RenderOneEvent(0, h, devicenames[devno]);       /* show name  */
  2118.         return(0);
  2119. }
  2120.  
  2121. /* ================================================================= */
  2122.  
  2123. int
  2124. RenderOneEvent(color, event, name)      /* draw event lines for active days */
  2125.         int color, event;
  2126.         char *name;
  2127. {
  2128.         register int y, day, dayflag, eventdays;
  2129.         int device;
  2130.  
  2131.         if (event == 0)
  2132.                 return(-1);
  2133.  
  2134. /* show the device name in proper color */
  2135.  
  2136.         device = Events[event].devicecode - 1;  /* device no. 0..n */
  2137.         y = ((device+1) * barsize) + Yorg;
  2138.  
  2139.         if (color <= 0)
  2140.                 intuitext.FrontPen = DEVNAMECOLOR;      /* normal color */
  2141.         else
  2142.                 intuitext.FrontPen = color;                     /* could be RED or TIMEFILLCOLOR */
  2143.  
  2144.         if (name)  {    /* if head of list */
  2145.                 intuitext.IText = textbuf;
  2146.                 intuitext.DrawMode = JAM1;
  2147.                 sprintf(textbuf, "%c%d %s",
  2148.                         ('A'-1)+BaseHouseCode+(device/16), (device & 15) + 1, name);
  2149.                 PrintIText(Rport, &intuitext, xmax+1, y);
  2150.         }
  2151.  
  2152.  
  2153.         if (color < 0)  {
  2154.                 SetAPen(Rport, TIMEFILLCOLOR);
  2155.                 RectFill(Rport, Events[event].xstart, y, Events[event].xstop, y+6);
  2156.                 return(0);
  2157.         }
  2158.  
  2159.         dayflag = 1;
  2160.         eventdays = Events[event].days;
  2161.  
  2162.         for (day = 0; day < 7; ++day) {
  2163.                 if (eventdays & dayflag)  {
  2164.                         if (color >= 0)
  2165.                                 SetAPen(Rport, color ? color : DAYCOLOR0 + day);
  2166.                         Move(Rport, Events[event].xstart, y+day);
  2167.                         Draw(Rport, Events[event].xstop, y+day);
  2168.                 }
  2169.                 dayflag *= 2;
  2170.         }
  2171.         return(0);
  2172. }
  2173.  
  2174. /* ================================================================= */
  2175.  
  2176. /*** Draw the regions for the events for each X10 device
  2177.      and show the device name as found in the disk file  */
  2178.  
  2179. int
  2180. TimeGraticule()
  2181. {
  2182.         register int device, x, y;
  2183.  
  2184.  
  2185.         DevAreaY = (deviceMax * barsize) + Yorg; /* smaller numbers are dev area */
  2186.  
  2187. /* Erase the event display area of screen */
  2188.         xmax = HourSpacing * 24;
  2189.         SetAPen(Rport, BLACK);
  2190.         RectFill(Rport, 8,Yorg, nw.MaxWidth-2, DevAreaY);
  2191.  
  2192. /* Draw horizontal box for each possible X10 device # and
  2193.     print the textual name of each device, as found in the data file. */
  2194.  
  2195.         intuitext.FrontPen = DEVNAMECOLOR;
  2196.         intuitext.DrawMode = JAM1;
  2197.         intuitext.IText = &textbuf[0];
  2198.         for (device = 0; device < deviceMax; ++device)  {
  2199.                 y = ((1+device) * barsize) + Yorg;
  2200.                 SetAPen(Rport, TIMEFILLCOLOR);
  2201.                 RectFill(Rport, 2, y, nw.MaxWidth, y+barheight);
  2202.                 sprintf(textbuf, "%c%d %s",
  2203.                         ('A'-1)+BaseHouseCode+(device/16),
  2204.                                 (device & 15) + 1, &devicenames[device+1]);
  2205.                 PrintIText(Rport, &intuitext, xmax+1, y);
  2206.         }
  2207.  
  2208.  
  2209. /* Draw AM/PM legends on display */
  2210.         y = DevAreaY + 16;
  2211.         intuitext.FrontPen = TIMELINECOLOR;
  2212.         intuitext.IText = "AM";
  2213.         PrintIText(Rport, &intuitext, 0, y);
  2214.         intuitext.IText = "PM";
  2215.         PrintIText(Rport, &intuitext, 13*HourSpacing, y);
  2216.         intuitext.IText = "N";
  2217.         PrintIText(Rport, &intuitext, (12 * HourSpacing) + 2, y);
  2218.  
  2219.  
  2220.         x = 12 * HourSpacing;
  2221.         SetAPen(Rport,TIMELINECOLOR);
  2222.         Move(Rport,  20, y+4);
  2223.         Draw(Rport,  x-2, y+4);
  2224.         Move(Rport, 14 * HourSpacing, y+4);
  2225.         Draw(Rport, 24 * HourSpacing, y+4);
  2226.         hourlines();                            /* add the vertical hour lines */
  2227.  
  2228.         return(0);
  2229. }
  2230.  
  2231. /* ================================================================= */
  2232.  
  2233. /*** Draw 24 lines vertically, depicting 24 hours/day */
  2234. static int hrlineflag = 1;
  2235.  
  2236. int
  2237. hourlines()
  2238. {
  2239.         register int y, hour, x, hh;
  2240.  
  2241.         intuitext.IText = &textbuf[0];
  2242.         intuitext.FrontPen = TIMELINECOLOR;
  2243.         intuitext.DrawMode = JAM1;
  2244.  
  2245.         y = DevAreaY + 10;
  2246.         x = 0;
  2247.         hh = 0;
  2248.  
  2249.         for (hour = 0; hour <= 24; ++hour)  {
  2250.                 SetAPen(Rport, TIMELINECOLOR);
  2251.                 Move(Rport, x, barsize);
  2252.                 Draw(Rport, x, y);
  2253.                 if (hrlineflag && hh)  {
  2254.                         sprintf(textbuf, "%2d", hh);
  2255.                         PrintIText(Rport, &intuitext, x - 8, y);
  2256.                 }
  2257.                 x += HourSpacing;
  2258.                 if (++hh > 12)
  2259.                         hh = 1;
  2260.         }
  2261.         hrlineflag = 0;
  2262.         return(0);
  2263. }
  2264.  
  2265. /* ================================================================= */
  2266.  
  2267. /*** Terminate program housekeeping */
  2268.  
  2269. int
  2270. cleanup()
  2271. {
  2272.         if (myplane)
  2273.                 FreeRaster(myplane,TMPRASX,TMPRASY);
  2274.         if (window)
  2275.                 CloseWindow(window);
  2276.         if (screen)
  2277.                 CloseScreen(screen);
  2278.         if (IntuitionBase)
  2279.                 CloseLibrary(IntuitionBase);
  2280.         if (GfxBase)
  2281.                 CloseLibrary(GfxBase);
  2282.         if (Serialisopen)  {
  2283.                 DeletePort( IORser.IOSer.io_Message.mn_ReplyPort );
  2284.                 CloseDevice( &IORser );
  2285.         }
  2286.  
  2287.  
  2288.         return(0);
  2289. }
  2290.  
  2291. /* ================================================================= */
  2292.  
  2293. /* return next in list for given day mask */
  2294.  
  2295. successor(eventno)
  2296.         int eventno;
  2297. {
  2298.         register int n;
  2299.  
  2300.         if ( (n = Events[eventno].link) == 0)
  2301.                 return(listhead(Events[eventno].devicecode));
  2302.  
  2303. #ifdef DAYMASK
  2304.         while ( (Events[n].days & Daymask) == 0)
  2305.                 if ( (n = Events[n].link) == 0)
  2306.                         break;
  2307. #endif
  2308.         return(n);
  2309. }
  2310.  
  2311. /* ================================================================= */
  2312.  
  2313. /* Return 1st in list for given day mask */
  2314. listhead(devno)
  2315.         int devno;
  2316. {
  2317.         register int n;
  2318.  
  2319.  
  2320.         n = devicelist[devno];
  2321.  
  2322. #ifdef DAYMASK
  2323.         while (n)
  2324.                 if (Events[n].days & Daymask)
  2325.                         break;
  2326.                 else
  2327.                         n = Events[n].link;
  2328. #endif
  2329.         return(n);
  2330. }